[email protected]

您所在的位置:网站首页 mount -o 参数 [email protected]

[email protected]

2023-04-13 18:54| 来源: 网络整理| 查看: 265

在前面

上一章,我们搞定了Vue官方文档里没有给出的,但在社区都在悄悄用的抽象组件,但是你知道,好东西不止于此...

今天,我们将搞定另一种牛的组件

老规矩,先上目录树

image.png

命令式组件

我们将借助Element UI 里的message组件实现命令式组件的基本原理.

什么是命令式组件 通过this去调用一个组件;也就是说使用extend将组件转为构造函数,在实例化这个这个构造函数后,就会得到$el属性,也就是组件的真实Dom,这个时候我们就可以操作得到的真实的Dom去任意挂载,使用命令式也可以调用。

用到的知识点:extend和$mount 官方文档

这两个都是vue提供的API,不过在平时的业务开发中使用并不多。在vue的内部也有使用过这一对API。遇到嵌套组件时,首先将子组件转为组件形式的VNode时,会将引入的组件对象使用extend转为子组件的构造函数,作为VNode的一个属性Ctor;然后在将VNode转为真实的Dom的时候实例化这个构造函数;最后实例化完成后手动调用$mount进行挂载,将真实Dom插入到父节点内完成渲染。 简单理解mount:手动挂载 ,Vue.extend作用:生成一个新的带有默认参数的Vue的子类

所以这个弹窗组件可以这样实现,我们自己对组件对象使用extend转为构造函数,然后手动调用$mount转为真实Dom,由我们来指定一个父节点让它插入到指定的位置。

新建message组件文件夹,然后再main.js导入组件,并use

image.png

在message/main.vue中,模仿Element ui 写一个message的组件 提示 此操作将永久删除该文件,是否确认删除 取消 确定 import Button from '@/components/Button/main.vue'; export default { name: 'cl-message-box', components: { Button } }; .cl-message-box { display: inline-block; width: 420px; padding-bottom: 10px; vertical-align: middle; background-color: #fff; border-radius: 4px; border: 1px solid #ebeef5; font-size: 18px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); text-align: left; overflow: hidden; backface-visibility: hidden; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -120%); &__header { position: relative; padding: 15px 15px 10px; } &__content { padding: 10px 15px; color: #606266; font-size: 14px; } &__btns { padding: 5px 15px 0; text-align: right; } &__content { padding: 10px 15px; color: #606266; font-size: 14px; } &__title { padding-left: 0; margin-bottom: 0; font-size: 18px; line-height: 1; color: #303133; } } 复制代码

在该组件index.js文件中导入,我们刚刚写好的组件,并生成一个MessageBox构造器,该构造器还应该是一个新的带有默认参数的Vue的子类,带有的默认参数比如就有template ,components

那么我们就要思考如何将这个组件渲染到页面上去呢? 我们只需要new这个MessageBox,让它成为一个实例,并执行mount方法触发vue的编译流程,挂载到$el上,然后使用正常的操作dom方法在其父节点中手动替换,然后在main.vue导入,这时候我们的message组件就会正常渲染到页面上,

但你要知道,此时虽然能正常渲染到页面,但它的渲染其实实际不受我们的控制,所以,我们需要将刚刚的代码用一个 $message函数包起来,然后在页面调用这个函数的执行,此时,我们的命令式组件的基本逻辑就已经实现啦,通过调用这个函数,让其组件在页面渲染

import Vue from 'vue/dist/vue'; import Main from './main.vue'; function $message() { // 实例化MessageBox组件 const messagebox = new MessageBox(); // 调用$mount()不传递参数 触发模板编译流程 messagebox.$mount(); // 通过messagebox实例的$el属性获取到编译后的结果 手动添加到页面中 document.body.appendChild(messagebox.$el); }); } //导入函数 export default $message; 复制代码 message box //导入 import { $message } from '../components/MessageBox'; export default { methods: { open() { //调用 $message(); }, }, }; 复制代码 我们希望,不需要导入,通过this就能调用该函数,则我们就需要,保存Vue实例,注册install方法,然后将将该函数挂载到Vue根实例原型,然后再全局引入,传入use 此时如果你看了element ui就会知道,我们的这个函数其实还需要传参

image.png 那么,我们又该如何实现呢?

我们也在open调用时传入三个参数,在我们定义的messagebox实例化时,在data里返回一个对象时传参进去,并且给默认值,插值表达式修改页面渲染内容 需求远远不够....我们看见,此时虽然页面能够正常渲染,但是,取消点不了哇!!☠ ☠ ☠ ☠,在index.jsdata设置标记变量messageboxVisiable:true,利v-if绑定标记变量 给按钮绑定点击事件,修改标记变量,此时就可以点击按钮控制messagebox的显示隐藏了

完善代码:

// import Vue from 'vue/dist/vue'; import Main from './main.vue'; let Vue = null; function message( message = '我是一条消息!', title = '标题', options = { confirmButtonText: '确定', cancelButtonText: '取消', type: 'info', } ) { // MessageBox是Vue类的子类 带有一些默认参数 比如template components const MessageBox = Vue.extend(Main); // 实例化MessageBox组件 const messagebox = new MessageBox({ // data() { return { message, title, options, //标记变量 messageBoxVisible: true, }; }, // 调用$mount()不传递参数 触发模板编译流程 messagebox.$mount(); // 通过messagebox实例的$el属性获取到编译后的结果 手动添加到页面中 document.body.appendChild(messagebox.$el); }); } message.install = function (_Vue) { Vue = _Vue; _Vue.prototype.$message = this; }; export default message; 复制代码 {{ title }} {{ message }} {{ options.confirmButtonText }} {{ options.cancelButtonText }} import Button from '@/components/Button/main.vue'; export default { name: 'cl-message-box', components: { Button }, methods: { hide() { this.messageBoxVisible = false; //优化,实例模板消失后,实例销毁 this.$nextTick(() => this.$destroy()); }, }, }; 复制代码 其实做到这里我们的组件就已经完成了,但是,佛说要高度还原,所以再看文档,发现是点取消后调用一个catch方法,确定调用then方法,分析得出,返回了Promise对象,于是继续改造呗!!!

得到组件最终版:

import Main from './main.vue'; let Vue = null; function message( message = '我是一条消息!', title = '标题', options = { confirmButtonText: '确定', cancelButtonText: '取消', type: 'info', } ) { return new Promise((resolve, reject) => { // MessageBox是Vue类的子类 带有一些默认参数 比如template components const MessageBox = Vue.extend(Main); // 实例化MessageBox组件 const messagebox = new MessageBox({ // data() { return { message, title, options, messageBoxVisible: true, }; }, methods: { resolve, reject, }, }); // 调用$mount()不传递参数 触发模板编译流程 messagebox.$mount(); // 通过messagebox实例的$el属性获取到编译后的结果 手动添加到页面中 document.body.appendChild(messagebox.$el); }); } message.install = function (_Vue) { Vue = _Vue; //挂载到原型 _Vue.prototype.$message = this; }; //导出 export default message; 复制代码 {{ title }} {{ message }} {{ options.confirmButtonText }} {{ options.cancelButtonText }} import Button from '@/components/Button/main.vue'; export default { name: 'cl-message-box', components: { Button }, methods: { hide() { this.messageBoxVisible = false; //优化,实例模板消失后,实例销毁 this.$nextTick(() => this.$destroy()); }, 调用时 cancal() { this.reject(); this.hide(); }, //成功时 confirm() { this.resolve(); this.hide(); }, }, }; 复制代码 最后

熬夜掉头发的感觉真的酸爽

但很多时候还是搞不明白逻辑,记不住,哎!! 这脑壳真差劲

谁来救救我啊!支点妙招



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3